package com.mapforge.gui.tools;

import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JRadioButton;
import javax.swing.JSpinner;
import javax.swing.SpinnerNumberModel;
import javax.swing.border.BevelBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import com.mapforge.map.tools.selection.AbstractSelectionTool;
import com.mapforge.selection.NullSelectionShapeModifier;
import com.mapforge.selection.SelectionFixedSizeModifier;
import com.mapforge.selection.SelectionProportionalSizeModifier;
import com.mapforge.selection.SelectionSquareSizeModifier;

public class SelectionToolControlPanel extends JPanel {
	/**
	 * Default serial version ID, here to remove warnings.
	 */
	private static final long serialVersionUID = 1L;

	private JPopupMenu optionsPopup;

	private JSpinner spnFixedWidth;
	private JSpinner spnFixedHeight;
	private JSpinner spnPropWidth;
	private JSpinner spnPropHeight;

	private JCheckBox chkFromCenter;
	private JCheckBox chkStroke;

	private JRadioButton radFixedSize;
	private JRadioButton radSquare;
	private JRadioButton radProportional;
	private JRadioButton radUnconstrained;

	private OptionsListener optionsListener;

	// selection shape modifiers
	private SelectionFixedSizeModifier fixedSizeModifier;
	private SelectionSquareSizeModifier squareModifier;
	private SelectionProportionalSizeModifier proportionalSizeModifier;
	private NullSelectionShapeModifier nullShapeModifier;

	AbstractSelectionTool selectionTool;

	public SelectionToolControlPanel(AbstractSelectionTool mapTool) {
		this.selectionTool = mapTool;

		this.optionsPopup = new JPopupMenu();
		this.optionsListener = new OptionsListener();

		// initialize shape modifiers
		this.fixedSizeModifier = new SelectionFixedSizeModifier(1, 1);
		this.squareModifier = new SelectionSquareSizeModifier();
		this.proportionalSizeModifier = new SelectionProportionalSizeModifier(
				1, 1);
		this.nullShapeModifier = NullSelectionShapeModifier.getHandle();

		this.chkStroke = new JCheckBox("Stroke", false);
		this.chkFromCenter = new JCheckBox("From Center", false);
		this.chkStroke.setOpaque(false);
		this.chkFromCenter.setOpaque(false);
		this.chkFromCenter.addActionListener(optionsListener);

		this.spnFixedWidth = createSpinner();
		this.spnFixedHeight = createSpinner();
		this.spnPropWidth = createSpinner();
		this.spnPropHeight = createSpinner();

		this.radUnconstrained = createRadio("Unconstrained");
		this.radSquare = createRadio("Square");
		this.radFixedSize = createRadio("Fixed Size");
		this.radProportional = createRadio("Proportional");
		ButtonGroup btnGroup = new ButtonGroup();
		btnGroup.add(this.radUnconstrained);
		btnGroup.add(this.radSquare);
		btnGroup.add(this.radFixedSize);
		btnGroup.add(this.radProportional);

		this.optionsPopup.setBorder(BorderFactory
				.createBevelBorder(BevelBorder.RAISED));
		Box optionsBox = Box.createVerticalBox();
		this.optionsPopup.add(optionsBox);
		optionsBox.add(wrapField(radUnconstrained));
		optionsBox.add(wrapField(radSquare));
		JPanel fixedPane = new JPanel(new GridLayout(1, 3));
		JPanel propPane = new JPanel(new GridLayout(1, 3));
		fixedPane.add(this.radFixedSize);
		fixedPane.add(this.wrapField("W:", this.spnFixedWidth, 2, 2));
		fixedPane.add(this.wrapField("H:", this.spnFixedHeight, 2, 2));
		propPane.add(this.radProportional);
		propPane.add(this.wrapField("W:", this.spnPropWidth, 2, 2));
		propPane.add(this.wrapField("H:", this.spnPropHeight, 2, 2));
		this.radUnconstrained.setSelected(true);
		optionsBox.add(fixedPane);
		optionsBox.add(propPane);
		this.optionsPopup.pack();

		JButton btnOpt = new JButton("OPTIONS");
		btnOpt.addActionListener(this.optionsListener);
		JPanel controlPane = new JPanel(new FlowLayout(FlowLayout.LEFT, 2, 2));
		controlPane.setMinimumSize(new Dimension(500, 500));
		controlPane.setOpaque(false);
		controlPane.add(chkStroke);
		controlPane.add(chkFromCenter);
		controlPane.add(btnOpt);
		add(controlPane);
	}

	private JRadioButton createRadio(String name) {
		JRadioButton b = new JRadioButton(name, false);
		b.addActionListener(optionsListener);
		return b;
	}

	private JSpinner createSpinner() {
		JSpinner spinner = new JSpinner(new SpinnerNumberModel(1, 1, 500, 1));
		spinner.addChangeListener(optionsListener);
		spinner.setEnabled(false);
		return spinner;
	}

	private JPanel wrapField(JComponent c) {
		return wrapField("", c, 0, 2);
	}

	private JPanel wrapField(String name, JComponent c, int hgap, int vgap) {
		JPanel p = new JPanel(new FlowLayout(FlowLayout.LEFT, hgap, vgap));
		if (!name.equals(""))
			p.add(new JLabel(name));
		p.add(c);
		return p;
	}

	private class OptionsListener implements ActionListener, ChangeListener {
		public void actionPerformed(ActionEvent e) {
			Object obj = e.getSource();
			if (obj instanceof JRadioButton) {
				if (obj == radFixedSize) {
					spnFixedWidth.setEnabled(true);
					spnFixedHeight.setEnabled(true);
					spnPropWidth.setEnabled(false);
					spnPropHeight.setEnabled(false);
					fixedSizeModifier.setModifyingFromCenter(chkFromCenter
							.isSelected());
					selectionTool.setSelectionModifier(fixedSizeModifier);
				} else if (obj == radProportional) {
					spnFixedWidth.setEnabled(false);
					spnFixedHeight.setEnabled(false);
					spnPropWidth.setEnabled(true);
					spnPropHeight.setEnabled(true);
					proportionalSizeModifier
							.setModifyingFromCenter(chkFromCenter.isSelected());
					selectionTool
							.setSelectionModifier(proportionalSizeModifier);
				} else if (obj == radSquare) {
					spnPropWidth.setEnabled(false);
					spnPropHeight.setEnabled(false);
					spnFixedWidth.setEnabled(false);
					spnFixedHeight.setEnabled(false);
					squareModifier.setModifyingFromCenter(chkFromCenter
							.isSelected());
					selectionTool.setSelectionModifier(squareModifier);
				} else if (obj == radUnconstrained) {
					spnPropWidth.setEnabled(false);
					spnPropHeight.setEnabled(false);
					spnFixedWidth.setEnabled(false);
					spnFixedHeight.setEnabled(false);
					nullShapeModifier.setModifyingFromCenter(chkFromCenter
							.isSelected());
					selectionTool.setSelectionModifier(nullShapeModifier);
				}
			} else if (obj instanceof JCheckBox) {
				if (obj == chkFromCenter) {
					if (chkFromCenter.isSelected()) {
						selectionTool.getSelectionModifier()
								.setModifyingFromCenter(true);
					} else {
						selectionTool.getSelectionModifier()
								.setModifyingFromCenter(false);
					}
				}
			} else if (obj instanceof JButton) {
				JButton btn = (JButton) obj;
				optionsPopup.show(btn, 0, btn.getHeight());
			}
		}

		@Override
		public void stateChanged(ChangeEvent e) {
			Object obj = e.getSource();
			if (obj == spnPropWidth) {
				proportionalSizeModifier
						.setProportionalWidth((Integer) spnPropWidth.getValue());
			} else if (obj == spnPropHeight) {
				proportionalSizeModifier
						.setProportionalHeight((Integer) spnPropHeight
								.getValue());
			} else if (obj == spnFixedWidth) {
				fixedSizeModifier.setWidth((Integer) spnFixedWidth.getValue());
			} else if (obj == spnFixedHeight) {
				fixedSizeModifier
						.setHeight((Integer) spnFixedHeight.getValue());
			}
		}
	}
}
